import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

public class Kombinatoorika extends JApplet {
	private static final long serialVersionUID = 1L;
	NupuPaneel nupupaneel = new NupuPaneel();
	MyCanvas mycanvas = new MyCanvas();

	class NupuPaneel extends JPanel implements ActionListener {
		private static final long serialVersionUID = 1L;
		int mitukuuli = 6, mituvalitud = 3, aeg = 2;
		boolean paus = false;
		JTextArea mitmest, mitmekaupa;
		JLabel mitmest_lbl, mitmekaupa_lbl;
		JButton rohkem_kuule, v2hem_kuule, start_anim, kiirenda_anim,
				aeglusta_anim, peata_anim, valitud_pluss, valitud_minus;
		ArrayList<ArrayList<Integer>> kyik_kombinatsioonid;

		NupuPaneel() {
			mitmest_lbl = new JLabel("Mitmest: ");
			mitmekaupa_lbl = new JLabel("Mitme kaupa: ");
			mitmest = new JTextArea("" + mitukuuli);
			mitmekaupa = new JTextArea("" + mituvalitud);
			rohkem_kuule = new JButton("n +");
			v2hem_kuule = new JButton("n -");
			valitud_pluss = new JButton("k +");
			valitud_minus = new JButton("k -");
			kiirenda_anim = new JButton("Kiirenda");
			aeglusta_anim = new JButton("Aeglusta");
			start_anim = new JButton("Käivita animatsioon");
			peata_anim = new JButton("Pane paus");
			rohkem_kuule.addActionListener(this);
			v2hem_kuule.addActionListener(this);
			valitud_pluss.addActionListener(this);
			valitud_minus.addActionListener(this);
			kiirenda_anim.addActionListener(this);
			aeglusta_anim.addActionListener(this);
			peata_anim.addActionListener(this);
			start_anim.addActionListener(this);
			mitmest.setEditable(false);
			mitmekaupa.setEditable(false);
			mitmest.setFont(new Font("Arial", 1, 20));
			mitmekaupa.setFont(new Font("Arial", 1, 20));

			this.add(mitmest_lbl);
			this.add(rohkem_kuule);
			this.add(v2hem_kuule);
			this.add(mitmest);
			this.add(mitmekaupa_lbl);
			this.add(valitud_pluss);
			this.add(valitud_minus);
			this.add(mitmekaupa);
			this.add(start_anim);
			this.add(kiirenda_anim);
			this.add(aeglusta_anim);
			this.add(peata_anim);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			String cmd = evt.getActionCommand();

			if (cmd == rohkem_kuule.getText()) {
				mycanvas.taimer.stop();
				mitukuuli ++;
				mycanvas.valimi_nr = 0;
				mycanvas.repaint();
			}
			if (cmd == v2hem_kuule.getText()) {
				mycanvas.taimer.stop();
				mitukuuli --;
				if (mitukuuli <= mituvalitud) {
					mituvalitud = mitukuuli;
				}
				mycanvas.valimi_nr = 0;
				mycanvas.repaint();
			}
			if (cmd == valitud_pluss.getText()) {
				mycanvas.taimer.stop();
				mituvalitud ++;
				if (mituvalitud >= mitukuuli) {
					mitukuuli = mituvalitud;
				}
				mycanvas.valimi_nr = 0;
				mycanvas.repaint();
			}
			if (cmd == valitud_minus.getText()) {
				mycanvas.taimer.stop();
				mituvalitud --;
				mycanvas.valimi_nr = 0;
				mycanvas.repaint();
			}
			
			nuppude_olekud();			
			
			mitmest.setText("" + mitukuuli);
			mitmekaupa.setText("" + mituvalitud);
			
			if (cmd == kiirenda_anim.getText()) {
				aeg = aeg + 1;
				if (aeg > 8) {
					aeg = 8;
				}
			}
			if (cmd == aeglusta_anim.getText()) {
				aeg = aeg - 1;
				if (aeg == 0) {
					aeg = 1;
				}
			}
			if (cmd == peata_anim.getText()) {
				if (paus) {
					paus = false;
					mycanvas.taimer.start();
					peata_anim.setText("Pane Paus");
				} else {
					paus = true;
					mycanvas.taimer.stop();
					peata_anim.setText("Jätka");
				}
			}
			if (cmd == start_anim.getText()) {
				tekita_kombinatsioonid();
				mycanvas.time = 1;
				mycanvas.taimer.start();
			}
		}
		
		public void nuppude_olekud () {
			if (mituvalitud < mitukuuli) {
				valitud_pluss.setEnabled(true);
				v2hem_kuule.setEnabled(true);
			}			
			if (mitukuuli > 19) {
				rohkem_kuule.setEnabled(false);
				valitud_pluss.setEnabled(false);
			}
			if (mitukuuli < 20 ) rohkem_kuule.setEnabled(true);
			if (mituvalitud < 20) valitud_pluss.setEnabled(true);

			if (mituvalitud > 1) valitud_minus.setEnabled(true);
			else valitud_minus.setEnabled(false);

			if (mitukuuli > 1) v2hem_kuule.setEnabled(true);
			else v2hem_kuule.setEnabled(false);
		}

		public ArrayList<ArrayList<Integer>> kombi(ArrayList<Integer> algseis, int suurus) {
			int kaupa = 0, yhtesid_l6pus;
			ArrayList<ArrayList<Integer>> kombinatsioonid = new ArrayList<ArrayList<Integer>>();
			kombinatsioonid.add(koopia(algseis));
			for(int i=0; algseis.get(i).intValue()==1 && i < suurus-1; i++, kaupa++) ;

			do {
				int nulle_l6pus = 0;
				for (int i = suurus - 1; i > 0 && algseis.get(i) == 0; i--) {
					nulle_l6pus++;
				}
				for (int i = suurus - nulle_l6pus - 1; nulle_l6pus > 0; nulle_l6pus--) {
					algseis.remove(suurus - 1);
					algseis.add(i, new Integer(0)); // liiguta viimast 1 l6ppu
					kombinatsioonid.add(koopia(algseis));
				}

				yhtesid_l6pus = 0;
				for (int i = suurus-1; algseis.get(i)==1 && i > 0; i--) {
					yhtesid_l6pus++;
				}
				for (int i = suurus - 1; i > 0 && yhtesid_l6pus > 0; i--) {
					if (algseis.get(i - 1).intValue() == 1 && algseis.get(i).intValue() == 0) {
						for (int k = 0; k < yhtesid_l6pus; k++) {
							algseis.add(i - 1, new Integer(1)); // lisa 1 niipalju kui on l6pus
							algseis.remove(suurus - 1);
						}
						algseis.remove(suurus - 1);
						algseis.add(i - 1, new Integer(0)); // nihuta paremale
						break;
					}
				}

				if(yhtesid_l6pus != kaupa) { // et l6pus kordust poleks, kui on 1 kaupa n-st
					kombinatsioonid.add(koopia(algseis)); // v6i n kaupa n-st
				}
			} while (yhtesid_l6pus != kaupa);

			return kombinatsioonid;
		}

		public ArrayList<Integer> koopia(ArrayList<Integer> massiiv) {
			ArrayList<Integer> massiiv_copy = new ArrayList<Integer>();
			massiiv_copy.addAll(massiiv);
			return massiiv_copy;
		}

		public void tekita_kombinatsioonid() {
			ArrayList<Integer> algseis = new ArrayList<Integer>();
			
			for(int i=0; i < mituvalitud; i++) {
				algseis.add(new Integer(1));
			}
			for(int i=0; i < mitukuuli - mituvalitud; i++) {
				algseis.add(new Integer(0));
			}

			kyik_kombinatsioonid = kombi(algseis, algseis.size());
		}

	}

	class MyCanvas extends JPanel {

		Timer taimer;
		int time = 1;
		int valimi_nr = 0;

		private static final long serialVersionUID = 593L;

		public MyCanvas() {
			super();
			taimer = new Timer(40, new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					time += nupupaneel.aeg;
					// if (time > 100) taimer.stop();
					repaint();
				}
			});
		}

		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			int mitukuuli = nupupaneel.mitukuuli;
			int mituvalitud = nupupaneel.mituvalitud, teepikkus, kerasuurus, fontsize;
			int h = getHeight(), w = getWidth(), suund=1, nihe=0, roheline=0, korgus_y;
			Graphics2D g2 = (Graphics2D) g;
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g2.drawLine(0, 0, w, 0);  // a:a:rejoon
			g2.drawLine(0, 0, 0, h);  // a:a:rejoon
			g2.drawLine(w-1, 0, w-1, h); // a:a:rejoon
			g2.drawLine(0, h-1, w, h-1); // a:a:rejoon
			korgus_y = (int) (h / 2.5);
			kerasuurus = Math.min(h /4 , w / (mitukuuli + 2));
			fontsize = Math.max(14, h / 22);
			
			if (taimer.isRunning()) {
				g2.setFont(new Font("Arial", 1, fontsize));
				g2.drawString("Kombinatsioonide arv " + mitukuuli + " -st  " + mituvalitud 
						+ " kaupa on " + nupupaneel.kyik_kombinatsioonid.size(), 20, 30);
				g2.setFont(new Font("Arial", 0, fontsize));
				g2.drawString("Kombinatsioon nr " + (valimi_nr + 1) + " / "
						+ nupupaneel.kyik_kombinatsioonid.size()
						+ "           Animatsiooni kiirus:"
						+ nupupaneel.aeg, 20, 60);

				ArrayList<Integer> uus_kombinatsioon = nupupaneel.kyik_kombinatsioonid.get(valimi_nr);

				for (int i = 0; i < uus_kombinatsioon.size(); i++) {
					Integer seisund = uus_kombinatsioon.get(i);
					int laius = w /mitukuuli * i;
					if (seisund.intValue() == 1) {
						
						if (time < 50) {
							suund = 1;
							nihe = 0;
							roheline = 0 + suund * time * 4;
						}
						else {
							suund = -1;
							nihe = 400;
							roheline = 4 * (100 + suund * time);
						}
						
						teepikkus = Math.min(kerasuurus , nihe + time * 4 * suund);
						
						if (roheline < 1) roheline = 0;
						
						g2.setColor(new Color(0, Math.min(15 + roheline, 130), 0));
						joonista_kuul(g2, laius , korgus_y - teepikkus,
								kerasuurus, kerasuurus);
					} else {
						g2.setColor(new Color(0, 0, 0));
						joonista_kuul(g2,laius, korgus_y,
								kerasuurus, kerasuurus);
					}
				} // end for
				
				if (time > 100) {
					valimi_nr++;
					if (valimi_nr == nupupaneel.kyik_kombinatsioonid.size()) {
						taimer.stop();
						valimi_nr = 0;
					}
					time = 1;
				}

			} else { // kui taimer seisab
				for (int i = 0; i < mitukuuli; i++) {
					g2.setColor(Color.black);
					int laius = w /mitukuuli * i;
					joonista_kuul(g2, laius, korgus_y, kerasuurus, kerasuurus);
				}
			}
		} // end paintComponent

		public void mouseDragged(MouseEvent e) {
		}

		public void mouseMoved(MouseEvent e) {
		}

		public void joonista_kuul(Graphics2D g2, int x, int y, int laius, int kyrgus) {
			g2.fillOval(x, y, laius, kyrgus);
		}

	}

	public void init() {
		setLayout(new BorderLayout());
		resize(900, 600);
		add(nupupaneel, BorderLayout.NORTH);
		add(mycanvas, BorderLayout.CENTER);
	}
}
